package com.ruoyi.common.swagger.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public class SwaggerAutoConfiguration {

    /**
     * 默认的排除路径，排除Spring Boot默认的错误处理路径和端点
     */
    private static final List<String> DEFAULT_EXCLUDE_PATH = List.of("/error", "/actuator/**");

    @Bean
    public OpenAPI customOpenAPI(SwaggerProperties swaggerProperties) {
        // 构建OpenAPI对象并初始化Components
        OpenAPI openAPI = new OpenAPI();
        openAPI.setComponents(new Components()); // 关键修复：显式初始化Components

        // 配置服务器信息
        if (swaggerProperties.getHost() != null && !swaggerProperties.getHost().isEmpty()) {
            Server server = new Server();
            server.setUrl(swaggerProperties.getHost());
            openAPI.addServersItem(server);
        }

        // 配置API基本信息
        Info info = new Info()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .termsOfService(swaggerProperties.getTermsOfServiceUrl());

        // 配置联系人信息
        if (swaggerProperties.getContact() != null) {
            Contact contact = new Contact()
                    .name(swaggerProperties.getContact().getName())
                    .url(swaggerProperties.getContact().getUrl())
                    .email(swaggerProperties.getContact().getEmail());
            info.setContact(contact);
        }

        // 配置许可证信息
        if (swaggerProperties.getLicense() != null && !swaggerProperties.getLicense().isEmpty()) {
            License license = new License()
                    .name(swaggerProperties.getLicense())
                    .url(swaggerProperties.getLicenseUrl());
            info.setLicense(license);
        }

        openAPI.setInfo(info);

        // 配置安全方案（JWT令牌）
        SecurityScheme securityScheme = new SecurityScheme()
                .type(SecurityScheme.Type.HTTP)
                .scheme("bearer")
                .bearerFormat("JWT")
                .in(SecurityScheme.In.HEADER)
                .name("Authorization");

        // 现在可以安全地使用components了，因为已经初始化
        openAPI.getComponents().addSecuritySchemes("Authorization", securityScheme);

        // 添加全局安全要求
        SecurityRequirement securityRequirement = new SecurityRequirement();
        securityRequirement.addList("Authorization");
        openAPI.addSecurityItem(securityRequirement);

        return openAPI;
    }

    /**
     * 配置路径包含与排除规则
     */
    @Bean
    public OpenApiCustomizer pathCustomizer(SwaggerProperties swaggerProperties) {
        return openApi -> {
            // 确保Paths对象已初始化
            if (openApi.getPaths() == null) {
                openApi.setPaths(new Paths());
            }

            // 处理排除路径
            List<String> excludePaths = new ArrayList<>(DEFAULT_EXCLUDE_PATH);
            if (!swaggerProperties.getExcludePath().isEmpty()) {
                excludePaths.addAll(swaggerProperties.getExcludePath());
            }

            // 应用排除规则
            openApi.getPaths().entrySet().removeIf(entry ->
                    excludePaths.stream().anyMatch(path ->
                            entry.getKey().matches(path.replace("**", ".*").replace("*", "[^/]*"))
                    )
            );
        };
    }
}
